package com.evil.activiti.listener;

import cn.hutool.core.collection.CollectionUtil;
import com.evil.activiti.enums.EventTypeEnum;
import com.evil.activiti.util.ActivityUtil;
import com.evil.application.api.RemoteApplicationOrderNodeService;
import com.evil.application.pojo.dto.order.node.AddOrderNodeBaseReqDTO;
import com.evil.application.pojo.dto.order.node.ModifyOrderNodeDataReqDTO;
import com.evil.common.account.dto.user.UserEnterpriseDTO;
import com.evil.common.activiti.enums.HandleTypeEnum;
import com.evil.common.activiti.enums.NodeTypeEnum;
import com.evil.common.core.enums.RCodeEnum;
import com.evil.common.core.exception.BusinessException;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.TaskListener;
import org.activiti.engine.impl.persistence.entity.TaskEntityImpl;
import org.activiti.engine.task.IdentityLink;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 流程处理人监听器
 *
 * @author 15587
 * @date 2022-08-08 00:00
 */
@Slf4j
@Component("TaskHandlerListener")
@AllArgsConstructor
public class TaskHandlerListener implements TaskListener {

    private final RemoteApplicationOrderNodeService remoteApplicationOrderNodeService;

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public void notify(DelegateTask delegateTask) {
        String eventName = delegateTask.getEventName();
        String flowId = delegateTask.getTaskDefinitionKey();
        String name = delegateTask.getName();
        Long orderId = delegateTask.getVariable(ActivityUtil.getProcessOrderIdKey(), Long.class);
        log.info("【流程处理人监听器】，节点id：{}, 节点name:{}", flowId, name);
        log.info("【流程处理人监听器】，订单id:{}", orderId);

        // 开始事件
        if (EventTypeEnum.CREATE.getEvent().equals(eventName)) {
            // 从节点中获取全部处理人并进行分组
            TaskEntityImpl taskEntity = (TaskEntityImpl) delegateTask;
            Map<String, List<IdentityLink>> groupIdentityMap = new ArrayList<>(taskEntity.getIdentityLinks()).stream()
                    // 业务特殊处理，当前的type 已经是业务上定义的分组id，已经脱离原来的 IdentityLinkType
                    .collect(Collectors.groupingBy(IdentityLink::getType));
            if (groupIdentityMap.isEmpty()) {
                throw new BusinessException(RCodeEnum.ACTIVITY_ASSIGNEE_NOT_EXIST).formatMessage(delegateTask.getName());
            }

            Map<String, Set<String>> groupIdentityLinks = new HashMap<>();
            List<UserEnterpriseDTO> nodeHandlers = new ArrayList<>();
            Map<String, List<UserEnterpriseDTO>> groupAssignees = new HashMap<>();

            groupIdentityMap.forEach((group, identityLinks) -> {
                Set<String> assignees = identityLinks.stream().map(IdentityLink::getUserId).collect(Collectors.toSet());
                groupIdentityLinks.put(group, assignees);

                List<UserEnterpriseDTO> handlers = ActivityUtil.restoreUserIds(assignees);
                nodeHandlers.addAll(handlers);
                groupAssignees.put(group, handlers);
            });

            // 获取本节点参数
            List<String> assignedList = ActivityUtil.getListForVariables(delegateTask.getExecution().getVariablesLocal(), ActivityUtil.ASSIGNED_LIST, String.class);
            boolean first = CollectionUtil.isEmpty(assignedList);
            String group = groupIdentityLinks.keySet().stream()
                    .filter(e -> !assignedList.contains(e))
                    .findFirst().orElseThrow(() -> new BusinessException(RCodeEnum.ACTIVITY_PROCESS_NODE_HANDLERS_ERROR));
            // 更新本届点参数
            assignedList.add(group);
            delegateTask.getExecution().setVariableLocal(ActivityUtil.ASSIGNED_LIST, assignedList);

            // 本节点当前次处理人
            ArrayList<String> assignees = new ArrayList<>(groupIdentityLinks.get(group));
            if (assignees.isEmpty()) {
                RCodeEnum codeEnum = RCodeEnum.ACTIVITY_ASSIGNEE_NOT_EXIST;
                throw new BusinessException(codeEnum, String.format(codeEnum.getMessage(), delegateTask.getName()));
            }
            // 节点当前次处理人
            delegateTask.setAssignee(assignees.get(0));
            // 节点当前次候选人
            delegateTask.addCandidateUsers(assignees);

            if (first) {
                this.addOrderNode(delegateTask, groupAssignees);
            }

            if (NodeTypeEnum.CARBON_COPY_NODE.getId() != ActivityUtil.restoreFlowNodeType(flowId)) {
                this.modifyOrderNodeData(delegateTask, nodeHandlers);
            }
        }
    }

    /**
     * 新的订单节点
     *
     * @param delegateTask   delegateTask
     * @param groupAssignees groupAssignees
     */
    private void addOrderNode(DelegateTask delegateTask, Map<String, List<UserEnterpriseDTO>> groupAssignees) {
        AddOrderNodeBaseReqDTO addOrderNodeBaseReqDTO = new AddOrderNodeBaseReqDTO();
        addOrderNodeBaseReqDTO.setGroupAssignees(groupAssignees);
        addOrderNodeBaseReqDTO.setOrderId(delegateTask.getVariable(ActivityUtil.getProcessOrderIdKey(), Long.class));

        String flowId = delegateTask.getTaskDefinitionKey();
        addOrderNodeBaseReqDTO.setNodeId(ActivityUtil.restoreFlowNodeId(flowId));
        if (NodeTypeEnum.CARBON_COPY_NODE.getId() == ActivityUtil.restoreFlowNodeType(flowId)) {
            addOrderNodeBaseReqDTO.setHandleType(HandleTypeEnum.CARBON.getId());
        } else {
            addOrderNodeBaseReqDTO.setHandleType(HandleTypeEnum.PROCESSING.getId());
        }

        // 流程节点记录
        remoteApplicationOrderNodeService.addOrderNode(addOrderNodeBaseReqDTO);
    }

    /**
     * 修改订单数据-节点数据
     *
     * @param delegateTask delegateTask
     * @param nodeHandlers nodeHandlers
     */
    private void modifyOrderNodeData(DelegateTask delegateTask, List<UserEnterpriseDTO> nodeHandlers) {
        // 节点与处理人信息
        Map<Long, List<UserEnterpriseDTO>> nodeHandlersMap = new HashMap<>();
        String flowId = delegateTask.getTaskDefinitionKey();
        Long currentNodeId = ActivityUtil.restoreFlowNodeId(flowId);
        for (DelegateExecution delegateExecution : new ArrayList<>(delegateTask.getExecution().getParent().getExecutions())) {
            String currentActivityId = delegateExecution.getCurrentActivityId();
            Long nodeId = ActivityUtil.restoreFlowNodeId(currentActivityId);
            NodeTypeEnum nodeTypeEnum = ActivityUtil.restoreFlowNodeTypeEnum(currentActivityId);
            if (nodeTypeEnum.isHasHandler()) {
                List<UserEnterpriseDTO> delegateHandlers = new ArrayList<>();
                if (flowId.equals(currentActivityId)) {
                    delegateHandlers.addAll(nodeHandlers);
                }
                nodeHandlersMap.put(nodeId, delegateHandlers);
            }
        }

        if (!nodeHandlersMap.isEmpty()) {
            // 更新订单节点数据
            ModifyOrderNodeDataReqDTO modifyOrderNodeDataReqDTO = new ModifyOrderNodeDataReqDTO();
            modifyOrderNodeDataReqDTO.setOrderId(delegateTask.getVariable(ActivityUtil.getProcessOrderIdKey(), Long.class));
            modifyOrderNodeDataReqDTO.setParentNodeId(delegateTask.getVariable(ActivityUtil.getSequenceFlowKey(currentNodeId), Long.class));
            modifyOrderNodeDataReqDTO.setNodeHandlersMap(nodeHandlersMap);
            modifyOrderNodeDataReqDTO.setHandleType(HandleTypeEnum.PROCESSING.getId());
            remoteApplicationOrderNodeService.modifyOrderNodeData(modifyOrderNodeDataReqDTO);
        }
    }
}
